namespace C4F.DevKit.Bluetooth
{
    namespace FileTransferProfile
    {
        #region Using Directives
        using System;
        using System.Collections.Generic;
        using System.Text;
        using System.Net.Sockets;
        using C4F.DevKit.Bluetooth.ObjectExchange;
        using System.IO;
        using System.Xml;
        using System.Threading;
        using System.ComponentModel;
        using Resources;
        #endregion

        /// <summary>
        /// Contains methods for performing file/folder operations on remote
        /// device.
        /// </summary>

        public class BluetoothFTPManager : Component
        {
            #region Private Members

            /// <summary>
            /// Network Stream used for communication with remote service
            /// </summary>
            private NetworkStream netwrkStream;

            /// <summary>
            /// Connection Id  used in all subsequent requests.
            /// </summary>
            private byte[] connectionId;

            /// <summary>
            /// Maximum Packet Length that the remote device accepts.
            /// </summary>
            private ushort maxPacketLength;

            /// <summary>
            /// List of pending FTPReqests.
            /// </summary>
            private List<FTPRequest> requestQueue;

            /// <summary>
            /// A background worker that handles asynchronous FTP requests.
            /// </summary>
            private BackgroundWorker asyncOperationHandler;

            /// <summary>
            /// The asynchronous FTP request that is being handled by 
            /// asyncOperationHandler.
            /// </summary>
            private FTPRequest runningAsyncRequest;

            #endregion

            #region Public Events and Delegates

            /// <summary>
            /// The event handler for an GetFileBegin event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Get File operation begins.
            /// </param>
            public delegate void GetFileBeginEventHandler(object sender,
                                                GetFileBeginEventArgs e);

            /// <summary>
            /// This event is fired when a Get File operation begins.
            /// </summary>
            public event GetFileBeginEventHandler GetFileBegin;

            /// <summary>
            /// The event handler for a GetFileCompleted event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Get File operation completes.
            /// </param>
            public delegate void GetFileCompletedEventHandler(object sender,
                                                GetFileCompletedEventArgs e);

            /// <summary>
            /// This event is fired when a Get File operation completes.
            /// </summary>
            public event GetFileCompletedEventHandler GetFileCompleted;

            /// <summary>
            /// The event handler for a GetFolderBegin event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Get Folder operation begins.
            /// </param>
            public delegate void GetFolderBeginEventHandler(object sender,
                                                GetFolderBeginEventArgs e);

            /// <summary>
            /// This event is fired when an Get Folder operation begins.
            /// </summary>
            public event GetFolderBeginEventHandler GetFolderBegin;

            /// <summary>
            /// The event handler for a GetFolderCompleted event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Get Folder operation 
            /// completes.</param>
            public delegate void GetFolderCompletedEventHandler(object sender,
                                                GetFolderCompletedEventArgs e);

            /// <summary>
            /// This event is fired when a Get Folder operation completes.
            /// </summary>
            public event GetFolderCompletedEventHandler GetFolderCompleted;

            /// <summary>
            /// The event handler for a SendFileBegin event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Send File operation begins.
            /// </param>
            public delegate void SendFileBeginEventHandler(object sender,
                                                SendFileBeginEventArgs e);

            /// <summary>
            /// This event is fired when an Send File operation begins.
            /// </summary>
            public event SendFileBeginEventHandler SendFileBegin;

            /// <summary>
            /// The event handler for a SendFileCompleted event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Send File operation 
            /// completes.</param>
            public delegate void SendFileCompletedEventHandler(object sender,
                                                SendFileCompletedEventArgs e);

            /// <summary>
            /// This event is fired when a Send File operation completes.
            /// </summary>
            public event SendFileCompletedEventHandler SendFileCompleted;

            /// <summary>
            /// The event handler for a SendFolderBegin event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Send Folder operation begins.
            /// </param>
            public delegate void SendFolderBeginEventHandler(object sender,
                                                SendFolderBeginEventArgs e);

            /// <summary>
            /// This event is fired when a SendFolder operation begins.
            /// </summary>
            public event SendFolderBeginEventHandler SendFolderBegin;

            /// <summary>
            /// The event handler for a SendFolderCompleted event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Send Folder operation 
            /// completes.</param>
            public delegate void SendFolderCompletedEventHandler(object sender,
                                               SendFolderCompletedEventArgs e);

            /// <summary>
            /// This event is fired when a Send Folder operation completes.
            /// </summary>
            public event SendFolderCompletedEventHandler SendFolderCompleted;

            /// <summary>
            /// The event handler for a DeleteFileBegin event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Delete File operation begins.
            /// </param>
            public delegate void DeleteFileBeginEventHandler(object sender,
                                                DeleteFileBeginEventArgs e);

            /// <summary>
            /// This event is fired when an Delete File operation begins.
            /// </summary>
            public event DeleteFileBeginEventHandler DeleteFileBegin;

            /// <summary>
            /// The event handler for an DeleteFileCompleted event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Delete File operation 
            /// completes.</param>
            public delegate void DeleteFileCompletedEventHandler(object sender,
                                               DeleteFileCompletedEventArgs e);

            /// <summary>
            /// This event is fired when a DeleteFile operation completes.
            /// </summary>
            public event DeleteFileCompletedEventHandler DeleteFileCompleted;

            /// <summary>
            /// The event handler for an DeleteFolderBegin event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Delete Folder operation 
            /// begins.</param>
            public delegate void DeleteFolderBeginEventHandler(object sender,
                                                DeleteFolderBeginEventArgs e);

            /// <summary>
            /// This event is fired when an DeleteFolder operation begins.
            /// </summary>
            public event DeleteFolderBeginEventHandler DeleteFolderBegin;

            /// <summary>
            /// The event handler for an DeleteFolderCompleted event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Delete Folder operation 
            /// completes.</param>
            public delegate void DeleteFolderCompletedEventHandler(object sender,
                                                DeleteFolderCompletedEventArgs e);

            /// <summary>
            /// This event is fired when a DeleteFolder operation completes.
            /// </summary>
            public event DeleteFolderCompletedEventHandler DeleteFolderCompleted;

            /// <summary>
            /// The event handler for a CreateFolderBegin event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Create Folder operation 
            /// begins.</param>
            public delegate void CreateFolderBeginEventHandler(object sender,
                                                CreateFolderBeginEventArgs e);

            /// <summary>
            /// This event is fired when a CreateFolder operation begins.
            /// </summary>
            public event CreateFolderBeginEventHandler CreateFolderBegin;

            /// <summary>
            /// The event handler for a CreateFolderCompleted event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a Create Folder operation 
            /// completes.</param>
            public delegate void CreateFolderCompletedEventHandler(object sender,
                                                CreateFolderCompletedEventArgs e);

            /// <summary>
            /// This event is fired when a CreateFolder operation completes.
            /// </summary>
            public event CreateFolderCompletedEventHandler CreateFolderCompleted;

            /// <summary>
            /// The event handler for a SetCurrentDirectoryBegin event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a SetCurrentDirectory operation
            /// begins.</param>
            public delegate void SetCurrentDirectoryBeginEventHandler(object sender,
                                                SetCurrentDirectoryBeginEventArgs e);

            /// <summary>
            /// This event is fired when a SetCurrentDirectory operation begins.
            /// </summary>
            public event SetCurrentDirectoryBeginEventHandler
                                                      SetCurrentDirectoryBegin;

            /// <summary>
            /// The event handler for a SetCurrentDirectoryCompleted event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a SetCurrentDirectory operation 
            /// completes.</param>
            public delegate void SetCurrentDirectoryCompletedEventHandler(object sender,
                                                SetCurrentDirectoryCompletedEventArgs e);

            /// <summary>
            /// This event is fired when a SetCurrentDirectory operation completes.
            /// </summary>
            public event SetCurrentDirectoryCompletedEventHandler
                                                SetCurrentDirectoryCompleted;


            /// <summary>
            /// The event handler for a GetFolderListingBegin event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a GetFolderListing operation
            /// begins.</param>
            public delegate void GetFolderListingBeginEventHandler(object sender,
                                                GetFolderListingBeginEventArgs e);

            /// <summary>
            /// This event is fired when a GetFolderListing operation begins.
            /// </summary>
            public event GetFolderListingBeginEventHandler GetFolderListingBegin;

            /// <summary>
            /// The event handler for a GetFolderListingCompleted event.
            /// </summary>
            /// <param name="sender">The sender of the event.</param>
            /// <param name="e">EventArgs when a GetFolderListing operation
            /// completes.</param>
            public delegate void GetFolderListingCompletedEventHandler(object sender,
                                                GetFolderListingCompletedEventArgs e);

            /// <summary>
            /// This event is fired when a GetFolderListing operation completes.
            /// </summary>
            public event GetFolderListingCompletedEventHandler
                                                        GetFolderListingCompleted;



            #endregion

            #region Public Functions

            #region Constructor
            /// <summary>
            /// Initializes a FTPManager object.
            /// </summary>
            public BluetoothFTPManager()
            {
                // Initialize request queue and background worker.
                InitializeFTPManager();
            }

            /// <summary>
            /// Initializes a FTPManager object.
            /// </summary>
            /// <param name="networkStream">Network stream used for 
            /// communication with remote service.</param>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to the method that does not accept it as a valid argument.
            /// </exception>            
            public BluetoothFTPManager(NetworkStream networkStream)
            {
                if (networkStream == null)
                    throw new ArgumentNullException(
                        FTPMessages.ErrorMsgNullNetworkStream);

                this.netwrkStream = networkStream;

                // Initialize request queue and background worker.
                InitializeFTPManager();
            }

            #endregion

            #region Asynchronous Methods

            /// <summary>
            /// Asynchronous operation for pulling a file from remote device
            /// </summary>
            /// <param name="remoteFilePath">Location of the file to be pulled 
            /// from remote device.</param>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the asynchronous request.</param>        
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a GetFile operation.
            /// </exception>

            public void GetFileAsync(string remoteFilePath, object userState)
            {
                //Verify if a valid value has been provided for remoteFilePath
                //argument.                
                if (string.IsNullOrEmpty(remoteFilePath))
                    throw new ArgumentNullException(
                        FTPMessages.RemoteFilePath);

                if (remoteFilePath.EndsWith("\\"))
                    throw new ArgumentException(
                                FTPMessages.ErrorMsgInvalidRemoteFilePath,
                                FTPMessages.RemoteFilePath);


                //Verify if connectionId is not null.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream property is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue
                AddRequestToRequestQueue(new FTPRequest(FTPRequestType.GetFile,
                                            userState,
                                            remoteFilePath));
            }

            /// <summary>
            /// Asynchronous operation for pulling a folder from remote device.
            /// </summary>
            /// <param name="remoteFolderPath">Location of folder to be pulled 
            /// from remote device.</param>
            /// <param name="localFolderPath">Location where pulled folder will
            /// be stored on local device.</param>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the request.</param>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a GetFolder operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            
            public void GetFolderAsync(string remoteFolderPath,
                                       string localFolderPath,
                                       object userState)
            {
                //Verify if remoteFolderPath is valid.
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);


                //If the remoteFolderPath ends with a directory seperator 
                //then remove it
                if (remoteFolderPath.EndsWith("\\") &&
                     remoteFolderPath != "\\")
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Verify if localFolderPath is valid.
                if (string.IsNullOrEmpty(localFolderPath))
                    throw new ArgumentNullException(
                        FTPMessages.LocalFolderPath);

                if (!Directory.Exists(localFolderPath))
                    throw new ArgumentException(
                        FTPMessages.ErrorMsgInvalidLocalFolderPath,
                        FTPMessages.LocalFolderPath);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue
                AddRequestToRequestQueue(new FTPRequest(FTPRequestType.GetFolder,
                                            userState,
                                            remoteFolderPath,
                                            localFolderPath));
            }

            /// <summary>
            /// Asynchronous operation for pushing a file on to remote device.
            /// </summary>
            /// <param name="localFilePath">Location of file on local device 
            /// that has to be pushed on to remote device.</param>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the request.</param>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a SendFile operation.
            /// </exception>            
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void SendFileAsync(string localFilePath, object userState)
            {
                //Verify if the specified localFilePath is valid.
                if (string.IsNullOrEmpty(localFilePath))
                    throw new ArgumentNullException
                            (FTPMessages.LocalFilePath);

                if (!File.Exists(localFilePath))
                    throw new ArgumentException
                        (FTPMessages.ErrorMsgInvalidLocalFilePath,
                        FTPMessages.LocalFilePath);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue
                AddRequestToRequestQueue(new FTPRequest(FTPRequestType.SendFile,
                                                        userState,
                                                        localFilePath));
            }

            /// <summary>
            /// Asynchronous operation for pushing a file on to remote device.
            /// </summary>
            /// <param name="fileContents">Memory Stream containing contents 
            /// of the file to be pushed on to remote device.</param>
            /// <param name="fileName">Name of the file which will be created 
            /// on remote device.</param>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the request.</param>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>         
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a SendFile operation.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void SendFileAsync(MemoryStream fileContents, string fileName, object userState)
            {
                //Verify if fileContents is valid.
                if (fileContents == null)
                    throw new ArgumentNullException(FTPMessages.FileContents);

                //Verify if fileName is valid.
                if (string.IsNullOrEmpty(fileName))
                    throw new ArgumentNullException(FTPMessages.FileName);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue
                AddRequestToRequestQueue(new FTPRequest(FTPRequestType.SendFile,
                                                        userState,
                                                        fileName,
                                                        fileContents));
            }

            ///<summary>
            ///Asynchronous operation for pushing a folder on to remote device.
            ///</summary>
            ///<param name="localFolderPath">Location of folder on local device 
            ///that has to be pushed on to remote device.</param>
            ///<param name="userState">A unique object which can be used to 
            ///keep track of the request.</param>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a SendFolder operation.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void SendFolderAsync(string localFolderPath, object userState)
            {

                //Verify if localFolderPath is valid.
                if (string.IsNullOrEmpty(localFolderPath))
                    throw new ArgumentNullException(FTPMessages.LocalFolderPath);

                if (!Directory.Exists(localFolderPath))
                    throw new ArgumentException(
                        FTPMessages.ErrorMsgInvalidLocalFolderPath,
                        FTPMessages.LocalFolderPath);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue
                AddRequestToRequestQueue(new FTPRequest(FTPRequestType.SendFolder,
                                                       userState,
                                                       localFolderPath));
            }

            /// <summary>
            /// Asynchronous operation for deleting a file from remote device.
            /// </summary>
            /// <param name="remoteFilePath">Location of file on remote device 
            /// that has to be deleted.</param>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the request.</param>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a DeleteFile operation.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void DeleteFileAsync(string remoteFilePath, object userState)
            {
                string fileName = string.Empty;

                //Verify if remoteFilePath is valid.
                if (string.IsNullOrEmpty(remoteFilePath))
                    throw new ArgumentNullException(FTPMessages.RemoteFilePath);

                if (remoteFilePath.EndsWith("\\"))
                    throw new ArgumentException(
                        FTPMessages.ErrorMsgInvalidRemoteFilePath,
                        FTPMessages.RemoteFilePath);


                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue.
                AddRequestToRequestQueue(new FTPRequest(FTPRequestType.DeleteFile,
                                                       userState,
                                                       remoteFilePath));
            }

            /// <summary>
            /// Asynchronous operation for deleting a folder from remote device.
            /// </summary>
            /// <param name="remoteFolderPath">Location of folder on remote 
            /// device that has to be deleted.</param>
            /// <param name="deleteSubDirectories">Flag indicating if sub-folders
            /// folders have to be deleted.If true then deletes sub-folders else 
            /// deletes only specified folder.</param>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the request.</param>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a DeleteFolder operation.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void DeleteFolderAsync(string remoteFolderPath,
                                          bool deleteSubDirectories,
                                          object userState)
            {
                //Verify if specified remoteFolderPath is valid
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.Equals("\\"))
                    throw new ArgumentException(
                                FTPMessages.ErrorMsgDeleteRootDir,
                                FTPMessages.RemoteFolderPath);


                if (remoteFolderPath.EndsWith("\\"))
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue
                AddRequestToRequestQueue(new FTPRequest(FTPRequestType.DeleteFolder,
                                                      userState,
                                                      remoteFolderPath,
                                                      deleteSubDirectories));

            }

            /// <summary>
            /// Asynchronous operation for creating a folder on remote device.
            /// </summary>
            /// <param name="remoteFolderPath">Location of the folder to be 
            /// created on remote device.The last folder in this path is assumed
            /// to be the folder which has to be created.</param>
            /// <param name="createParentDirectories">Flag indicating if non-existing
            /// parent folders have to be created.If true then creates 
            /// non-existing parent folders. If false and if parent folder doesn't exist 
            /// then an exception is raised.</param>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the request.</param>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a CreateFolder operation.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void CreateFolderAsync(string remoteFolderPath,
                                          bool createParentDirectories,
                                          object userState)
            {
                //Verify if the remoteFolderPath is valid
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.Equals("\\"))
                    throw new ArgumentException(FTPMessages.ErrorMsgCreateRootDir,
                                                FTPMessages.RemoteFolderPath);



                if (remoteFolderPath.EndsWith("\\"))
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue.
                AddRequestToRequestQueue(new FTPRequest
                                            (FTPRequestType.CreateFolder,
                                             userState,
                                             remoteFolderPath,
                                             createParentDirectories));
            }

            /// <summary>
            /// Asynchronous operation for setting the current directory 
            /// on remote device.
            /// </summary>
            /// <param name="remoteFolderPath">Location of remote folder 
            /// to be set as current directory.</param>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the request.</param>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>    
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a SetCurrentDirectory operation.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void SetCurrentDirectoryAsync(string remoteFolderPath, object userState)
            {
                //Verify if Path is valid.
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.EndsWith("\\") &&
                    remoteFolderPath.Length > 2)
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue.
                AddRequestToRequestQueue(new FTPRequest(FTPRequestType.SetCurrentDirectory,
                                                                  userState,
                                                                  remoteFolderPath));

            }

            /// <summary>
            /// Asynchronous operation for getting the folder listing of a 
            /// remote folder.
            /// </summary>
            /// <param name="remoteFolderPath">Location of folder on remote 
            /// device.</param>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the request.</param>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>       
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a GetFolderListing operation.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void GetFolderListingAsync(string remoteFolderPath, object userState)
            {
                //Verify if remoteFolderPath is valid.
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.EndsWith("\\") &&
                    remoteFolderPath.Length > 2)
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Add request to queue.
                AddRequestToRequestQueue(new FTPRequest(FTPRequestType.GetFolderListing,
                                                                  userState,
                                                                  remoteFolderPath));
            }

            /// <summary>
            /// Cancels an asynchronous operation.
            /// </summary>
            /// <param name="userState">A unique object which can be used to 
            /// keep track of the request.</param>
            /// <exception cref="InvalidOperationException">Thrown when 
            /// an error occurs while trying to cancel a non-existent FTPRequest.</exception>
            public void CancelAsync(object userState)
            {
                if (userState == null)
                    throw new ArgumentNullException(FTPMessages.UserState);

                bool invalidCancel = true;
                //Acquire an exclusive lock on the requestQueue. 
                Monitor.Enter(this.requestQueue);

                try
                {
                    // Check whether this operation is currently executing.
                    if (this.asyncOperationHandler.IsBusy
                        && this.runningAsyncRequest != null
                        && this.runningAsyncRequest.UserState.Equals(userState))
                    {
                        this.asyncOperationHandler.CancelAsync();
                        invalidCancel = false;
                    }
                    else
                    {
                        // Search for the operation in the queue.
                        foreach (FTPRequest request in this.requestQueue)
                        {
                            if (request.UserState.Equals(userState))
                            {
                                //Remove it from queue.
                                this.requestQueue.Remove(request);
                                invalidCancel = false;
                                break;
                            }
                        }
                    }
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.requestQueue);
                }

                // The userState was not found. Raise a InvalidOperationException 
                //exception
                if (invalidCancel)
                    throw new InvalidOperationException
                                        (FTPMessages.ErrorMsgInvalidUserState);
            }

            #endregion

            #region Synchronous Methods

            /// <summary>
            /// Synchronous operation for pulling a file from remote device.
            /// </summary>
            /// <param name="remoteFilePath">Location of the file to be pulled
            /// from remote device.</param>   
            /// <returns>Contents of the pulled file.</returns>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a GetFile operation.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public byte[] GetFile(string remoteFilePath)
            {
                byte[] fileStream = null;

                //Verify if the remoteFilePath is valid.
                if (string.IsNullOrEmpty(remoteFilePath))
                    throw new ArgumentNullException(FTPMessages.RemoteFilePath);

                if (remoteFilePath.EndsWith("\\"))
                    throw new ArgumentException(
                                    FTPMessages.ErrorMsgInvalidRemoteFilePath,
                                    FTPMessages.RemoteFilePath);

                //Verify if the connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Raise the GetFileBegin Event.              
                if (GetFileBegin != null)
                    GetFileBegin(this,
                                 new GetFileBeginEventArgs(remoteFilePath,
                                                           null));

                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);

                try
                {
                    //Get the file object and return byte array containing 
                    //the file contents.
                    fileStream = GetFileObject(remoteFilePath);

                    //Raise the GetFileCompleted Event   
                    if (GetFileCompleted != null)
                        GetFileCompleted(this,
                          new GetFileCompletedEventArgs(remoteFilePath,
                                                            fileStream,
                                                            null,
                                                            false,
                                                            null));

                    return fileStream;
                }

                catch (Exception ex)
                {

                    //Raise the GetFileCompleted event
                    if (GetFileCompleted != null)
                        GetFileCompleted(this,
                         new GetFileCompletedEventArgs(remoteFilePath,
                                                       fileStream,
                                                       ex,
                                                       false,
                                                       null));
                    throw new FTPException(FTPMessages.ErrorMsgGetFile,
                                           ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);

                }
            }

            /// <summary>
            /// Synchronous operation for pulling a folder from remote device.
            /// </summary>
            /// <param name="remoteFolderPath">Location of folder to be pulled 
            /// from remote device.</param>
            /// <param name="localFolderPath">Location where pulled folder will
            /// be stored on local device.</param>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a GetFolder operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void GetFolder(string remoteFolderPath, string localFolderPath)
            {
                //Verify if remoteFolderPath is valid.
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.EndsWith("\\") &&
                    remoteFolderPath != "\\")
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Verify if localFolderPath is valid.
                if (string.IsNullOrEmpty(localFolderPath))
                    throw new ArgumentNullException(FTPMessages.LocalFolderPath);

                if (!Directory.Exists(localFolderPath))
                    throw new ArgumentException(
                        FTPMessages.ErrorMsgInvalidLocalFolderPath,
                        FTPMessages.LocalFolderPath);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Raise the GetFolderBegin event
                if (GetFolderBegin != null)
                    GetFolderBegin(this,
                                   new GetFolderBeginEventArgs(remoteFolderPath,
                                                               localFolderPath,
                                                               null));

                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);


                try
                {
                    //Call GetFolderObject function which performs the actual task of
                    //pulling a folder.

                    GetFolderObject(remoteFolderPath, localFolderPath);

                    //Raise the GetFolderCompleted event
                    if (GetFolderCompleted != null)
                        GetFolderCompleted(
                                   this,
                                   new GetFolderCompletedEventArgs(remoteFolderPath,
                                                                   localFolderPath,
                                                                   null,
                                                                   false,
                                                                   null));
                }
                catch (Exception ex)
                {
                    //Raise the GetFolderCompleted event
                    if (GetFolderCompleted != null)
                        GetFolderCompleted(
                                   this,
                                   new GetFolderCompletedEventArgs(remoteFolderPath,
                                                                   localFolderPath,
                                                                   ex,
                                                                   false,
                                                                   null));
                    throw new FTPException(FTPMessages.ErrorMsgGetFolder,
                                          ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);
                }

            }

            /// <summary>
            /// Synchronous operation for pushing a file on remote device.
            /// </summary>
            /// <param name="localFilePath">Location of file on local device 
            /// that has to be pushed on to remote device.</param>        
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a SendFile operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void SendFile(string localFilePath)
            {
                //Verify if the specified localFilePath is valid.
                if (string.IsNullOrEmpty(localFilePath))
                    throw new ArgumentNullException(FTPMessages.LocalFilePath);

                if (!File.Exists(localFilePath))
                    throw new ArgumentException
                            (FTPMessages.ErrorMsgInvalidLocalFilePath,
                             FTPMessages.LocalFilePath);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Raise the SendFileBegin event
                if (SendFileBegin != null)
                    SendFileBegin(this,
                                  new SendFileBeginEventArgs(localFilePath,
                                                             null));
                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);


                try
                {
                    //Call SendFileObject function which performs the actual 
                    //task of pushing file on remote device.
                    SendFileObject(localFilePath);

                    //Raise the SendFileCompleted event.
                    if (SendFileCompleted != null)
                        SendFileCompleted(this,
                                          new SendFileCompletedEventArgs(
                                                                localFilePath,
                                                                null,
                                                                false,
                                                                null));
                }
                catch (Exception ex)
                {
                    //Raise the SendFileCompleted event.
                    if (SendFileCompleted != null)
                        SendFileCompleted(this,
                                          new SendFileCompletedEventArgs(
                                                                localFilePath,
                                                                ex,
                                                                false,
                                                                null));

                    throw new FTPException(FTPMessages.ErrorMsgSendFile,
                                           ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);
                }
            }

            /// <summary>
            /// Synchronous operation for pushing a file on remote device.
            /// </summary>
            /// <param name="fileContents">Memory Stream containing the contents
            /// of the file.</param>        
            /// <param name="fileName">Name of the file which will be created on
            /// remote device.</param>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a SendFile operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>       
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void SendFile(MemoryStream fileContents, string fileName)
            {
                //Verify if fileContents is valid.
                if (fileContents == null)
                    throw new ArgumentNullException(FTPMessages.FileContents);

                //Verify if fileName is valid.
                if (string.IsNullOrEmpty(fileName))
                    throw new ArgumentNullException(FTPMessages.FileName);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Raise the SendFileBegin event
                if (SendFileBegin != null)
                    SendFileBegin(this, new SendFileBeginEventArgs(fileName,
                                                                    null));
                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);

                try
                {

                    //Call SendFileObject function which performs the actual 
                    //task of pushing file on remote device.                   
                    SendFileObject(fileContents, fileName);

                    //Raise the SendFileCompleted event.
                    if (SendFileCompleted != null)
                        SendFileCompleted(this,
                                          new SendFileCompletedEventArgs
                                                                    (fileName,
                                                                    null,
                                                                    false,
                                                                    null));
                }
                catch (Exception ex)
                {
                    //Raise the SendFileCompleted event.                    
                    if (SendFileCompleted != null)
                        SendFileCompleted(this,
                                          new SendFileCompletedEventArgs
                                                                    (fileName,
                                                                    null,
                                                                    false,
                                                                    null));

                    throw new FTPException(FTPMessages.ErrorMsgSendFile,
                                           ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);
                }

            }

            /// <summary>
            /// Synchronous operation for pushing a folder to remote device.
            /// </summary>
            /// <param name="localFolderPath">Location of folder on local device
            /// that has to be pushed on to remote device.</param>       
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a SendFolder operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void SendFolder(string localFolderPath)
            {
                //Verify if localFolderPath is valid.
                if (string.IsNullOrEmpty(localFolderPath))
                    throw new ArgumentNullException(FTPMessages.LocalFolderPath);

                if (!Directory.Exists(localFolderPath))
                    throw new ArgumentException(
                        FTPMessages.ErrorMsgInvalidLocalFolderPath,
                        FTPMessages.LocalFolderPath);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Raise the SendFolderBegin event.
                if (SendFolderBegin != null)
                    SendFolderBegin(this,
                                    new SendFolderBeginEventArgs(localFolderPath,
                                                                 null));

                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);


                try
                {

                    //Call SendFileObject function which performs the actual 
                    //task of pushing a folder on remote device.                               
                    SendFolderObject(localFolderPath);

                    //Raise the SendFolderCompleted event.
                    if (SendFolderCompleted != null)
                        SendFolderCompleted(this,
                                            new SendFolderCompletedEventArgs(
                                                                   localFolderPath,
                                                                   null,
                                                                   false,
                                                                   null));
                }
                catch (Exception ex)
                {
                    //Raise the SendFolderCompleted Event
                    if (SendFolderCompleted != null)
                        SendFolderCompleted(this,
                                            new SendFolderCompletedEventArgs(
                                                                   localFolderPath,
                                                                   ex,
                                                                   false,
                                                                   null));

                    throw new FTPException(FTPMessages.ErrorMsgSendFolder,
                                           ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);
                }

            }

            /// <summary>
            /// Synchronous operation for deleting a file from remote device.
            /// </summary>
            /// <param name="remoteFilePath">Location of file on remote device 
            /// that has to be deleted.</param>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a DeleteFile operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void DeleteFile(string remoteFilePath)
            {
                //Verify if remoteFilePath is valid.
                if (string.IsNullOrEmpty(remoteFilePath))
                    throw new ArgumentNullException(FTPMessages.RemoteFilePath);

                if (remoteFilePath.EndsWith("\\"))
                    throw new ArgumentException(
                        FTPMessages.ErrorMsgInvalidRemoteFilePath,
                        FTPMessages.RemoteFilePath);


                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Raise the DeleteFileBegin event
                if (DeleteFileBegin != null)
                    DeleteFileBegin(this, new DeleteFileBeginEventArgs(
                                                             remoteFilePath,
                                                             null));
                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);


                try
                {
                    //Call DeleteFileObject function which performs the actual 
                    //task of deleting a folder on remote device.      
                    DeleteFileObject(remoteFilePath);

                    //Raise the DeleteFileCompleted event
                    if (DeleteFileCompleted != null)
                        DeleteFileCompleted(this,
                                            new DeleteFileCompletedEventArgs(
                                                                 remoteFilePath,
                                                                 null,
                                                                 false,
                                                                 null));
                }
                catch (Exception ex)
                {
                    //Raise the DeleteFileCompleted event
                    if (DeleteFileCompleted != null)
                        DeleteFileCompleted(this,
                                            new DeleteFileCompletedEventArgs(
                                                                 remoteFilePath,
                                                                 ex,
                                                                 false,
                                                                 null));

                    throw new FTPException(FTPMessages.ErrorMsgDeleteFile,
                                           ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);
                }

            }

            /// <summary>
            /// Synchronous operation for deleting a folder from remote device.
            /// </summary>
            /// <param name="remoteFolderPath">Location of folder on remote 
            /// device that has to be deleted.</param>
            /// <param name="deleteSubDirectories">Flag indicating if sub-folders
            /// folders have to be deleted.If true then deletes sub-folders else 
            /// deletes only specified folder.</param>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a DeleteFolder operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void DeleteFolder(string remoteFolderPath, bool deleteSubDirectories)
            {

                //Verify if specified path is valid
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.Equals("\\"))
                    throw new ArgumentException(
                                FTPMessages.ErrorMsgDeleteRootDir,
                                FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.EndsWith("\\"))
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);


                //Raise the DeleteFolderCompleted event
                if (DeleteFolderBegin != null)
                    DeleteFolderBegin(this,
                                      new DeleteFolderBeginEventArgs(
                                                           remoteFolderPath,
                                                           deleteSubDirectories,
                                                           null));

                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);


                try
                {
                    DeleteFolderObject(remoteFolderPath, deleteSubDirectories);

                    //Raise the DeleteFolderCompleted event
                    if (DeleteFolderCompleted != null)
                        DeleteFolderCompleted(this,
                                              new DeleteFolderCompletedEventArgs
                                                                 (remoteFolderPath,
                                                                 deleteSubDirectories,
                                                                 null,
                                                                 false,
                                                                 null));
                }
                catch (Exception ex)
                {
                    //Raise the DeleteFolderCompleted event
                    if (DeleteFolderCompleted != null)
                        DeleteFolderCompleted(this,
                                              new DeleteFolderCompletedEventArgs
                                                                  (remoteFolderPath,
                                                                  deleteSubDirectories,
                                                                  ex,
                                                                  false,
                                                                  null));

                    throw new FTPException(FTPMessages.ErrorMsgDeleteFolder,
                                          ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);
                }
            }

            /// <summary>
            /// Synchronous operation for creating a folder on remote device.
            /// </summary>
            /// <param name="remoteFolderPath">Location of the folder to be 
            /// created on remote device.The last folder in this path is assumed
            /// to be the folder which has to be created.</param>
            /// <param name="createParentDirectories">Flag indicating if non-existing
            /// parent folders have to be created.If true then creates 
            /// non-existing parent folders. If false and if parent folder doesn't exist 
            /// then an exception is raised.</param>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a CreateFolder operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void CreateFolder(string remoteFolderPath, bool createParentDirectories)
            {

                //Verify if the remoteFolderPath is valid.
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.Equals("\\"))
                    throw new ArgumentException(FTPMessages.ErrorMsgCreateRootDir,
                                                FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.EndsWith("\\"))
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Verify if the connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Raise the CreateFolderBegin event
                if (CreateFolderBegin != null)
                    CreateFolderBegin(this,
                                      new CreateFolderBeginEventArgs(remoteFolderPath,
                                                                    createParentDirectories,
                                                                    null));
                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);

                try
                {
                    //Call CreateFolderStructure function which performs the actual 
                    //task of creating the folder on remote device.    
                    CreateFolderStructure(remoteFolderPath, createParentDirectories);

                    //Raise the CreateFolderCompleted event
                    if (CreateFolderCompleted != null)
                        CreateFolderCompleted(this,
                                              new CreateFolderCompletedEventArgs(
                                                                  remoteFolderPath,
                                                                  createParentDirectories,
                                                                  null,
                                                                  false,
                                                                  null));
                }
                catch (Exception ex)
                {
                    //Raise the CreateFolderCompleted event
                    if (CreateFolderCompleted != null)
                        CreateFolderCompleted(this,
                                              new CreateFolderCompletedEventArgs(
                                                                   remoteFolderPath,
                                                                   createParentDirectories,
                                                                   ex,
                                                                   false,
                                                                   null));

                    throw new FTPException(FTPMessages.ErrorMsgCreateFolder,
                                         ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);
                }
            }

            /// <summary>
            /// Synchronous operation for getting the folder listing of a remote folder.
            /// </summary>
            /// <param name="remoteFolderPath">Location of folder on remote 
            /// device.</param>
            /// <returns>Returns the folder Listing in a XML Document format.
            /// </returns>                      
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a GetFolderListing operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>      
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public XmlDocument GetFolderListing(string remoteFolderPath)
            {
                XmlDocument folderListingDoc = null;

                //Verify if remoteFolderPath is valid.
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);


                if (remoteFolderPath.EndsWith("\\") &&
                    remoteFolderPath.Length > 2)
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Verify if connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Raise the GetFolderListingBegin event.
                if (GetFolderListingBegin != null)
                    GetFolderListingBegin(this,
                                          new GetFolderListingBeginEventArgs(
                                                                 remoteFolderPath,
                                                                    null));
                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);

                try
                {
                    //Call GetFolderListingObject function which performs the 
                    //actual task of getting the folder listing of folder on 
                    //remote device.
                    folderListingDoc = GetFolderListingObject(remoteFolderPath);

                    //Raise the GetFolderListingCompleted event.
                    if (GetFolderListingCompleted != null)
                        GetFolderListingCompleted(this,
                                                  new GetFolderListingCompletedEventArgs(
                                                                       remoteFolderPath,
                                                                       folderListingDoc,
                                                                       null,
                                                                       false,
                                                                       null));

                    return folderListingDoc;
                }
                catch (Exception ex)
                {
                    //Raise the GetFolderListingCompleted event
                    if (GetFolderListingCompleted != null)
                        GetFolderListingCompleted(this,
                                                  new GetFolderListingCompletedEventArgs(
                                                                          remoteFolderPath,
                                                                          folderListingDoc,
                                                                          ex,
                                                                          false,
                                                                          null));

                    throw new FTPException(FTPMessages.ErrorMsgGetFolderListing,
                                         ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);
                }
            }

            /// <summary>
            /// Synchronous operation for setting the current directory on 
            /// remote device.
            /// </summary>
            /// <param name="remoteFolderPath">Location of remote folder to be 
            /// set as current directory.</param>
            /// <exception cref="FTPException">Thrown when 
            /// an error occurs while performing a SetCurrentDirectory operation.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when 
            /// when a null reference (not set or empty) is passed 
            /// to a method that does not accept it as a valid argument.
            /// </exception>     
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void SetCurrentDirectory(string remoteFolderPath)
            {

                //Verify if remoteFolderPath is valid.
                if (string.IsNullOrEmpty(remoteFolderPath))
                    throw new ArgumentNullException(FTPMessages.RemoteFolderPath);

                if (remoteFolderPath.EndsWith("\\") &&
                    remoteFolderPath.Length > 2)
                    remoteFolderPath =
                        remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Verify connectionId is valid.
                if (this.connectionId == null)
                    throw new FTPException(FTPMessages.ErrorMessageNullConnId);

                //Verify that the NetworkStream is set
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Raise the SetCurrentDirectoryBegin event.
                if (SetCurrentDirectoryBegin != null)
                    SetCurrentDirectoryBegin(this,
                        new SetCurrentDirectoryBeginEventArgs(
                                                        remoteFolderPath,
                                                        null));
                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);


                try
                {
                    //Call SetCurrentDirectoryObject function which performs the 
                    //actual task of setting the current directory on 
                    //remote device.
                    SetCurrentDirectoryObject(remoteFolderPath);

                    //Raise the SetCurrentDirectoryCompleted event
                    if (SetCurrentDirectoryCompleted != null)
                        SetCurrentDirectoryCompleted(this,
                            new SetCurrentDirectoryCompletedEventArgs(remoteFolderPath,
                                                                        null,
                                                                        false,
                                                                        null));
                }
                catch (Exception ex)
                {
                    //Raise the SetCurrentDirectoryCompleted event
                    if (SetCurrentDirectoryCompleted != null)
                        SetCurrentDirectoryCompleted(this,
                           new SetCurrentDirectoryCompletedEventArgs(remoteFolderPath,
                                                                     ex,
                                                                     false,
                                                                     null));

                    throw new FTPException(FTPMessages.ErrorMsgSetCurrentDir,
                                          ex);
                }
                finally
                {
                    //Releases the exclusive lock on networkStream
                    Monitor.Exit(this.netwrkStream);
                }
            }

            /// <summary>
            /// Connects to the file transfer service.
            /// </summary>   
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the Connect operation on remote device. 
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void Connect()
            {

                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);

                //Obex packet for connect to a File transfer service
                ObjectExchangeItem objectExchangeItemRequest =
                        new ObjectExchangeItem(ObjectExchangeOpcode.Connect);

                //Add a Obex Version Number fields.
                objectExchangeItemRequest.AddHeader
                        (ObjectExchangeHeaderType.ObexVersionNumber,
                        new byte[] { 0x10 });

                //Add a Flag fields
                objectExchangeItemRequest.AddHeader
                        (ObjectExchangeHeaderType.Flags,
                         new byte[] { 0x00 });

                objectExchangeItemRequest.AddHeader
                        (ObjectExchangeHeaderType.Target,
                        new byte[] { 0xF9, 0xEC, 
                                     0x7B, 0xC4, 
                                     0x95, 0x3C, 
                                     0x11, 0xD2, 
                                     0x98, 0x4E, 
                                     0x52, 0x54, 
                                     0x00, 0xDC, 
                                     0x9E, 0x09 });
                objectExchangeItemRequest.AddHeader
                        (ObjectExchangeHeaderType.MaxObexPacketLength,
                         new byte[] { 0x20, 0x00 });

                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);

                try
                {
                    //put the obex packet on te network stream
                    this.netwrkStream.Write
                                (objectExchangeItemRequest.GetByteStream(),
                                 0,
                                 objectExchangeItemRequest.PacketSize);

                    //Wait till data is available on  network stream
                    while (!this.netwrkStream.DataAvailable)
                        continue;
                    //Sleep for 1 second till all data is put on stream.
                    Thread.Sleep(1000);

                    MemoryStream responseStream =
                                  new MemoryStream();



                    //Read the response from stream
                    while (this.netwrkStream.DataAvailable)
                        responseStream.WriteByte
                                    ((byte)this.netwrkStream.ReadByte());

                    long position =
                            responseStream.Seek(0, SeekOrigin.Begin);


                    ObjectExchangeItem objectExchangeItemResponse =
                                    new ObjectExchangeItem(responseStream);


                    if (objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.Success ||
                       objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.SuccessFinal)
                    {
                        ObjectExchangeHeaderType[] headerTypes
                                 = objectExchangeItemResponse.GetHeaderTypes();

                        foreach (ObjectExchangeHeaderType headerType in
                                                            headerTypes)
                        {
                            if (headerType ==
                                     ObjectExchangeHeaderType.ConnectionID)
                            {
                                //store the connection id 
                                this.connectionId =
                                 new byte[objectExchangeItemResponse.GetHeader(headerType).Length];
                                this.connectionId =
                                 objectExchangeItemResponse.GetHeader(headerType);
                            }
                            if (headerType ==
                                    ObjectExchangeHeaderType.MaxObexPacketLength)
                            {
                                //store the max packet length received from remote device.
                                this.maxPacketLength =
                                 ObjectExchangeHelper.FormatUInt16
                                  (BitConverter.ToUInt16(objectExchangeItemResponse.GetHeader(headerType), 0));

                            }
                        }
                    }
                    else
                        ObjectExchangeHelper.RaiseObjectExchangeError
                                            (objectExchangeItemResponse.Opcode);                    
                  
                    return;
                }
                finally
                {
                    //Release the lock on the networkstream
                    Monitor.Exit(this.netwrkStream);

                }
            }

            /// <summary>
            /// Disconnects from FTP service
            /// </summary>        
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the Disconnect operation on remote device. 
            /// </exception>
            /// <exception cref="InvalidOperationException">Exception that is thrown when a 
            /// method call is invalid for the object's current state.            
            /// </exception>
            public void Disconnect()
            {
                if (this.netwrkStream == null)
                    throw new InvalidOperationException(
                        FTPMessages.Error_NetworkStreamNotSet);
                        

                //Obex packet for disonnecting from service.
                ObjectExchangeItem objectExchangeItemRequest =
                    new ObjectExchangeItem(ObjectExchangeOpcode.Disconnect);

                //Add ConnectionId header
                objectExchangeItemRequest.AddHeader
                    (ObjectExchangeHeaderType.ConnectionID, this.connectionId);

                //Acquire an exclusive lock on the networkStream. 
                Monitor.Enter(this.netwrkStream);

                try
                {
                    //puts the request on network stream
                    this.netwrkStream.Write(objectExchangeItemRequest.GetByteStream(),
                                       0,
                                       objectExchangeItemRequest.PacketSize);

                    //Wait till data is available on  network stream
                    while (!this.netwrkStream.DataAvailable)
                        continue;

                    MemoryStream responseStream = new MemoryStream();

                    //Sleep for 1 second till all data is put on stream.
                    Thread.Sleep(1000);

                    //Read response from stream
                    while (this.netwrkStream.DataAvailable)
                        responseStream.WriteByte
                            ((byte)this.netwrkStream.ReadByte());

                    long position = responseStream.Seek(0, SeekOrigin.Begin);
                    ObjectExchangeItem objectExchangeItemResponse =
                        new ObjectExchangeItem(responseStream);

                    //Verify the response code

                    if (objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.Success ||
                       objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.SuccessFinal)
                        return;
                    else
                        ObjectExchangeHelper.RaiseObjectExchangeError
                                        (objectExchangeItemResponse.Opcode);
                

                }
                finally
                {
                    //Release the lock on the networkstream
                    Monitor.Exit(this.netwrkStream);


                }
            }
            #endregion

            #endregion

            #region Private Functions
            /// <summary>
            /// Initializes FTPManager object.
            /// </summary>
            private void InitializeFTPManager()
            {
                //Initialize the list used to maintain pending asynchronous 
                //FTPRequest.
                this.requestQueue = new List<FTPRequest>();

                // Initialize the DoWork event handler of BackgroundWorker.
                this.asyncOperationHandler = new BackgroundWorker();
                this.asyncOperationHandler.DoWork +=
                    new DoWorkEventHandler(asyncOperationHandler_DoWork);

                //Initializes the RunWorkerCompleted event handler of 
                //BackgroundWorker.
                this.asyncOperationHandler.RunWorkerCompleted +=
                    new RunWorkerCompletedEventHandler(
                                asyncOperationHandler_RunWorkerCompleted);
                this.asyncOperationHandler.WorkerSupportsCancellation = true;
            }

            /// <summary>
            /// Sets the specified folder as current folder on remote device.
            /// </summary>
            /// <param name="remoteFolderName">Name of the folder to be set as 
            /// current folder on remote device.</param>
            /// <returns>Returns true if folder set as current folder else returns
            /// false.</returns>                              
            private bool SetCurrentFolder(string remoteFolderName)
            {
                try
                {
                    ObjectExchangeItem objectExchangeItemRequest = null;
                    MemoryStream responseStream = null;
                    ObjectExchangeItem objectExchangeItemResponse = null;

                    //Obex packet for setting current folder to root folder.
                    if (remoteFolderName.Equals(string.Empty))
                    {
                        //Initiailize the objectExchangeItem object with an
                        //opcode of SetPath
                        objectExchangeItemRequest =
                            new ObjectExchangeItem(ObjectExchangeOpcode.SetPath);

                        //Add flags field
                        objectExchangeItemRequest.AddHeader
                            (ObjectExchangeHeaderType.Flags,
                              new byte[] { 0x02 });

                        //Adds Constants field.
                        objectExchangeItemRequest.AddHeader
                            (ObjectExchangeHeaderType.Constants,
                             new byte[] { 0x00 });

                        //Adds connectionId header
                        objectExchangeItemRequest.AddHeader
                            (ObjectExchangeHeaderType.ConnectionID, this.connectionId);

                        //Adds name header
                        objectExchangeItemRequest.AddHeader
                            (ObjectExchangeHeaderType.Name, new byte[] { });
                    }
                    //Obex packet for setting current folder to parent folder.
                    else if (remoteFolderName.Equals(FTPMessages.ParentFolder))
                    {
                        //Initiailize the objectExchangeItem object with an opcode 
                        //of SetPath
                        objectExchangeItemRequest =
                            new ObjectExchangeItem(ObjectExchangeOpcode.SetPath);

                        //Add flags field
                        objectExchangeItemRequest.AddHeader
                          (ObjectExchangeHeaderType.Flags, new byte[] { 0x03 });

                        //Adds Constants field.
                        objectExchangeItemRequest.AddHeader
                          (ObjectExchangeHeaderType.Constants, new byte[] { 0x00 });

                        //Adds connectionId header
                        objectExchangeItemRequest.AddHeader
                           (ObjectExchangeHeaderType.ConnectionID, this.connectionId);
                    }
                    //obex packet for setting current folder to a child folder.
                    else if (!remoteFolderName.Equals(FTPMessages.CurrentFolder))
                    {
                        //Initiailize the objectExchangeItem object with an opcode 
                        //of SetPath
                        objectExchangeItemRequest =
                          new ObjectExchangeItem(ObjectExchangeOpcode.SetPath);

                        //Add flags field
                        objectExchangeItemRequest.AddHeader
                          (ObjectExchangeHeaderType.Flags, new byte[] { 0x02 });

                        //Adds Constants field.
                        objectExchangeItemRequest.AddHeader
                           (ObjectExchangeHeaderType.Constants, new byte[] { 0x00 });

                        //Adds connectionId header
                        objectExchangeItemRequest.AddHeader
                           (ObjectExchangeHeaderType.ConnectionID, this.connectionId);

                        //Adds name header
                        objectExchangeItemRequest.AddHeader
                           (ObjectExchangeHeaderType.Name, remoteFolderName
                            + "\0");
                    }

                    //Put request on network stream.
                    netwrkStream.Write(objectExchangeItemRequest.GetByteStream(),
                                       0,
                                       objectExchangeItemRequest.PacketSize);

                    //Wait for response
                    while (!this.netwrkStream.DataAvailable)
                        continue;

                    responseStream = new MemoryStream();
                    //Sleep for 1 second till all data is put on stream.
                    Thread.Sleep(1000);

                    //Read response from network stream.
                    while (this.netwrkStream.DataAvailable)
                        responseStream.WriteByte((byte)this.netwrkStream.ReadByte());

                    long position = responseStream.Seek(0, SeekOrigin.Begin);
                    objectExchangeItemResponse =
                        new ObjectExchangeItem(responseStream);

                    if (objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.Success ||
                      objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.SuccessFinal)
                        return true;
                    else
                        return false;
                    
                }
                catch
                {
                    //In an error occurs return false.
                    return false;
                }
            }

            /// <summary>
            /// Gets the folder listing of the current folder.
            /// </summary>
            /// <returns>Returns a XMLDocument containing the folder listing in
            /// XML Format.</returns> 
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception>            
            private XmlDocument GetCurrentFolderListingObject()
            {
                byte[] fileData = null;
                MemoryStream fileStream = new MemoryStream();
                BinaryWriter fileWriter = new BinaryWriter(fileStream);
                XmlDocument folderListingDocument = new XmlDocument();

                ObjectExchangeItem objectExchangeItemRequest = null;
                MemoryStream responseStream = null;
                ObjectExchangeItem objectExchangeItemResponse = null;

                bool continueGet = false;

                //Obex packet for Getting the FolderListing of remote 
                //folder.
                do
                {
                    //Initiailize the objectExchangeItem object with an
                    //opcode of Get
                    objectExchangeItemRequest =
                     new ObjectExchangeItem(ObjectExchangeOpcode.GetFinal);

                    //Add these headers only in the first request of Get
                    if (!continueGet)
                    {
                        //Add a connectionId header
                        objectExchangeItemRequest.AddHeader
                            (ObjectExchangeHeaderType.ConnectionID,
                             this.connectionId);

                        //Add a name header
                        objectExchangeItemRequest.AddHeader
                            (ObjectExchangeHeaderType.Name,
                             new byte[] { });

                        //Add a type header
                        objectExchangeItemRequest.AddHeader
                            (ObjectExchangeHeaderType.Type,
                             FTPMessages.FolderListingFormat);
                    }

                    //Put the request on the network stream
                    this.netwrkStream.Write(objectExchangeItemRequest.GetByteStream(),
                                       0,
                                       objectExchangeItemRequest.PacketSize);

                    //Waits for response
                    while (!this.netwrkStream.DataAvailable)
                        continue;

                    responseStream = new MemoryStream();

                    //Sleep for 1 second till all data is put on stream.
                    Thread.Sleep(1000);

                    //Reads the response from network stream.
                    while (this.netwrkStream.DataAvailable)
                        responseStream.WriteByte((byte)this.netwrkStream.ReadByte());

                    long position = responseStream.Seek(0, SeekOrigin.Begin);
                    objectExchangeItemResponse =
                        new ObjectExchangeItem(responseStream);

                    //Verify the response code.
                    if (objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.Continue ||
                       objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.ContinueFinal)
                    {
                        if (objectExchangeItemResponse.HeaderTypeExists
                                               (ObjectExchangeHeaderType.Body))

                            fileWriter.Write
                                (objectExchangeItemResponse.GetHeader
                                            (ObjectExchangeHeaderType.Body));
                        continueGet = true;
                    }

                    if((objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.Success ||
                       objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.SuccessFinal))
                    {
                         if (objectExchangeItemResponse.HeaderTypeExists
                                            (ObjectExchangeHeaderType.EndOfBody))
                                fileWriter.Write
                                    (objectExchangeItemResponse.GetHeader
                                            (ObjectExchangeHeaderType.EndOfBody));

                            fileData = fileStream.ToArray();
                            fileWriter.Close();

                            string folderContents = Encoding.ASCII.GetString(fileData);

                            if (folderContents.Contains(FTPMessages.FolderListingTag))
                            {
                                //Get the position of FolderListing tag in the 
                                //folderContents string
                                int iPos =
                                   folderContents.IndexOf(FTPMessages.FolderListingTag);

                                //Extracts folderListing string.
                                string folderListing =
                                    folderContents.Substring(iPos);

                                //Loads the xml document with the folderListing document.
                                folderListingDocument.LoadXml(folderListing);
                            }
                            continueGet = false;
                    }
                        //Raise the error
                    else
                        ObjectExchangeHelper.RaiseObjectExchangeError
                                  (objectExchangeItemResponse.Opcode);                  
                    
                }
                while (continueGet);
                return folderListingDocument;
            }

            /// <summary>
            /// Deletes a folder and its sub-folders.This function recursively
            /// deletes the folders along with its contents. 
            /// </summary>
            /// <param name="remoteFolderName">Name of the folder to be deleted.
            /// </param>
            /// <exception cref="ObjectExchangeException">Throws an ObjectExchangeException
            /// indicating that an error has occured while performing the 
            /// operation on remote device. </exception>           
            private void DeleteWithSubFolders(string remoteFolderName)
            {
                //Sets the current folder.
                if (SetCurrentFolder(remoteFolderName))
                {
                    XmlDocument doc = null;

                    //Gets the folder listing of current folder.
                    doc = GetCurrentFolderListingObject();

                    if (doc != null)
                    {
                        //Get list of folders
                        XmlNodeList folderList =
                                doc.GetElementsByTagName(FTPMessages.Folder);

                        //Get list of files
                        XmlNodeList fileList =
                                doc.GetElementsByTagName(FTPMessages.File);

                        //Delete all files in the fileList
                        if (fileList != null && fileList.Count != 0)
                        {
                            foreach (XmlNode node in fileList)
                            {
                                XmlAttributeCollection attrCollection =
                                                        node.Attributes;

                                if (attrCollection != null &&
                                        attrCollection.Count != 0)
                                {
                                    //Retrieve the name of the file.
                                    XmlNode attrNode =
                                        attrCollection.GetNamedItem(FTPMessages.Name);

                                    //Delete the file
                                    if (attrNode != null)
                                        DeleteObject(attrNode.Value);
                                }
                            }
                        }

                        //Delete all folders in the folderList.
                        if (folderList != null && folderList.Count != 0)
                        {
                            if (folderList.Count > 0)
                            {
                                foreach (XmlNode node in folderList)
                                {
                                    XmlAttributeCollection attrCollection =
                                                            node.Attributes;
                                    if (attrCollection != null &&
                                        attrCollection.Count != 0)
                                    {
                                        //Retrieve the name of the folder.
                                        XmlNode attrNode =
                                            attrCollection.GetNamedItem(FTPMessages.Name);

                                        if (attrNode != null)
                                        {
                                            //Recursive call. Delete the folder.
                                            DeleteWithSubFolders(attrNode.Value);
                                        }
                                    }
                                }
                            }
                        }
                        //If empty folder then delete it.
                        if (SetCurrentFolder(FTPMessages.ParentFolder))
                            DeleteObject(remoteFolderName);
                    }
                }

            }

            /// <summary>
            /// Traverses the file path and deletes the file.
            /// </summary>
            /// <param name="remoteFilePath">Location of file on remote device.</param>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception> 
            /// <exception cref="ArgumentException">Thrown when 
            /// one of the arguments provided to the method is not valid.
            /// </exception>
            private void DeleteFileObject(string remoteFilePath)
            {
                string fileName = string.Empty;

                //Split remoteFilePath on Directory Seperator.
                char[] delimeters = new char[] { '\\' };
                string[] folders = remoteFilePath.Split(delimeters);
                bool bRoot = false;

                //Indicates the first directory is root folder.  
                //Set the flag bRoot to true.
                if (folders[0] == string.Empty)
                    bRoot = true;

                //Traverse the folder hierarchy. Set the current 
                //directory on remote device.
                for (int i = 0; i < folders.Length - 1; i++)
                {
                    //Ignore further 
                    if (folders[i] == string.Empty && i != 0 && bRoot)
                        continue;

                    if (!SetCurrentFolder(folders[i]))
                        throw new ArgumentException
                           (FTPMessages.ErrorMsgInvalidRemoteFilePath,
                            FTPMessages.RemoteFilePath);
                }

                fileName = folders[folders.Length - 1];

                if (string.IsNullOrEmpty(fileName))
                    throw new ArgumentException
                           (FTPMessages.ErrorMsgInvalidRemoteFilePath,
                            FTPMessages.RemoteFilePath);

                //Delets the file.
                DeleteObject(fileName);
            }

            /// <summary>
            /// Deletes a file/folder from remote device.
            /// </summary>
            /// <param name="objectName">Name of the object to be deleted.
            /// </param>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the operation on remote device.</exception>                       
            private void DeleteObject(string objectName)
            {
                ObjectExchangeItem objectExchangeItemRequest = null;
                MemoryStream responseStream = null;
                ObjectExchangeItem objectExchangeItemResponse = null;

                //Initialize the objectExchangeItem with an opcode of Put
                objectExchangeItemRequest =
                    new ObjectExchangeItem(ObjectExchangeOpcode.PutFinal);

                //Add connectionId header
                objectExchangeItemRequest.AddHeader
                         (ObjectExchangeHeaderType.ConnectionID, this.connectionId);

                //Add Name header
                objectExchangeItemRequest.AddHeader
                            (ObjectExchangeHeaderType.Name,
                             objectName + "\0");

                //Puts the request on network stream.
                this.netwrkStream.Write(objectExchangeItemRequest.GetByteStream(),
                                   0,
                                   objectExchangeItemRequest.PacketSize);

                //Waits for response from the remote device.
                while (!this.netwrkStream.DataAvailable)
                    continue;

                //Sleep for 1 second till all data is put on stream.
                Thread.Sleep(1000);

                //Reads response from stream.
                responseStream = new MemoryStream();
                while (this.netwrkStream.DataAvailable)
                    responseStream.WriteByte((byte)this.netwrkStream.ReadByte());

                long position =
                    responseStream.Seek(0, SeekOrigin.Begin);

                objectExchangeItemResponse =
                            new ObjectExchangeItem(responseStream);

                //verify the response code.
                if (objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.Success ||
                   objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.SuccessFinal)
                    return;
                else
                    ObjectExchangeHelper.RaiseObjectExchangeError
                            (objectExchangeItemResponse.Opcode);
                
            }

            /// <summary>
            /// Pushes a file on to remote device.
            /// </summary>
            /// <param name="remoteFilePath">Location of the file to be pushed 
            /// on to remote device.</param>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the operation on remote device.</exception>  
            private void SendFileObject(string remoteFilePath)
            {
                //Retrieve the file name 
                string fileName = Path.GetFileName(remoteFilePath);

                //Extract contents of file.
                MemoryStream fileContents = new MemoryStream
                                              (File.ReadAllBytes(remoteFilePath));


                //Calls the SendFileObject overload
                SendFileObject(fileContents, fileName);
            }

            /// <summary>
            /// Pushes a file to remote device.
            /// </summary>
            /// <param name="fileContents">MemoryStream containing the file 
            /// contents.</param>
            /// <param name="fileName">Name of file to be created on remote 
            /// device.</param>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception>
            private void SendFileObject(MemoryStream fileContents, string fileName)
            {
                byte[] fileContent = fileContents.ToArray();

                MemoryStream fileStream = new MemoryStream(fileContent);
                BinaryReader fileReader = new BinaryReader(fileStream);

                // Create the Put request.
                List<ObjectExchangeItem> putRequestPackets =
                                        new List<ObjectExchangeItem>();

                //Initialize a objectExchangeItem with the Put opcode.
                ObjectExchangeItem objectExchangeItemRequest =
                            new ObjectExchangeItem(ObjectExchangeOpcode.Put);

                //Add name header
                objectExchangeItemRequest.AddHeader
                                    (ObjectExchangeHeaderType.Name, fileName);

                //Add length header
                objectExchangeItemRequest.AddHeader
                    (ObjectExchangeHeaderType.Length,
                     BitConverter.GetBytes
                                   (ObjectExchangeHelper.FormatUInt32
                                   (Convert.ToUInt32(fileContent.Length))));


                long bytesLeftToRead = fileStream.Length;

                // Object is large. So split the Object into packets.
                // 1st packet.
                if ((objectExchangeItemRequest.PacketSize + bytesLeftToRead + 3)
                                                    > this.maxPacketLength)
                {

                    int noOfBytesToRead =
                        this.maxPacketLength - objectExchangeItemRequest.PacketSize - 3;

                    //Add Body Header
                    objectExchangeItemRequest.AddHeader
                        (ObjectExchangeHeaderType.Body, fileReader.ReadBytes(noOfBytesToRead));

                    bytesLeftToRead -= noOfBytesToRead;
                    putRequestPackets.Add(objectExchangeItemRequest);

                    while (bytesLeftToRead > 0)
                    {
                        objectExchangeItemRequest =
                            new ObjectExchangeItem(ObjectExchangeOpcode.Put);
                        if (bytesLeftToRead >
                            (this.maxPacketLength - objectExchangeItemRequest.PacketSize - 3))
                        {
                            noOfBytesToRead =
                                this.maxPacketLength - objectExchangeItemRequest.PacketSize - 3;

                            //Add Body Header
                            objectExchangeItemRequest.AddHeader
                                (ObjectExchangeHeaderType.Body,
                                 fileReader.ReadBytes(noOfBytesToRead));
                        }
                        else
                        {
                            //Last packet.
                            objectExchangeItemRequest.Opcode =
                                    ObjectExchangeOpcode.PutFinal;

                            noOfBytesToRead = (int)bytesLeftToRead;

                            //Add an EndOfBody Header
                            objectExchangeItemRequest.AddHeader
                                (ObjectExchangeHeaderType.EndOfBody,
                                  fileReader.ReadBytes(noOfBytesToRead));
                        }

                        bytesLeftToRead -= noOfBytesToRead;
                        //Add packet to list
                        putRequestPackets.Add(objectExchangeItemRequest);
                    }
                }
                // Object fits in 1 packet.
                else
                {
                    objectExchangeItemRequest.Opcode =
                                    ObjectExchangeOpcode.PutFinal;

                    objectExchangeItemRequest.AddHeader
                            (ObjectExchangeHeaderType.EndOfBody,
                             fileReader.ReadBytes((int)bytesLeftToRead));

                    //Add packet to queue
                    putRequestPackets.Add(objectExchangeItemRequest);
                }


                //loop through the packets in the list and put them
                //on network stream one by one.
                for (int packetNo = 0; packetNo < putRequestPackets.Count;
                                                                packetNo++)
                {
                    byte[] putRequestBytes = putRequestPackets[packetNo].GetByteStream();
                    MemoryStream putResponseStream = new MemoryStream();
                    try
                    {
                        // Send the Put request.
                        this.netwrkStream.Write(putRequestBytes, 0, putRequestBytes.Length);

                        //Sleep for 1 second till all data is put on stream.
                        Thread.Sleep(1000);

                        while (!this.netwrkStream.DataAvailable)
                            continue;

                        // Read the response.
                        while (this.netwrkStream.DataAvailable)
                            putResponseStream.WriteByte((byte)this.netwrkStream.ReadByte());

                        putResponseStream.Seek(0, SeekOrigin.Begin);
                    }

                    catch (IOException ioEx)
                    {
                        throw new ObjectExchangeException
                                (ObjectExchangeErrorType.StreamError,
                                FTPMessages.ErrorMsgWritetoStream, ioEx);
                    }

                    catch (ObjectDisposedException objEx)
                    {
                        throw new ObjectExchangeException
                            (ObjectExchangeErrorType.StreamError,
                            FTPMessages.ErrorMsgWritetoStream, objEx);
                    }

                    ObjectExchangeItem objectExchangeItemResponse =
                                new ObjectExchangeItem(putResponseStream);

                    //Verify the response code
                    if (objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.Success ||
                        objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.SuccessFinal)
                        return;

                    if (objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.Continue ||
                        objectExchangeItemResponse.Opcode == ObjectExchangeOpcode.ContinueFinal)
                        continue;

                    else
                        ObjectExchangeHelper.RaiseObjectExchangeError
                                      (objectExchangeItemResponse.Opcode);
                  
                }
            }

            /// <summary>
            /// Pushes a folder on remote device.
            /// </summary>
            /// <param name="localFolderPath">Location of folder to be pushed 
            /// on to remote device </param>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception>
            private void SendFolderObject(string localFolderPath)
            {

                DirectoryInfo directoryObject =
                            new DirectoryInfo(localFolderPath);

                //Create folder on remote device.
                CreateFolderObject(directoryObject.Name);

                //Get a list of files present in the directory
                FileInfo[] files = directoryObject.GetFiles();

                //Pushes a each file on to remote device.
                foreach (FileInfo fileInfo in files)
                {

                    SendFileObject(fileInfo.FullName);
                    //SendFileObject(fileInfo.DirectoryName +
                    //               "\\" +
                    //               fileInfo.ToString());
                }

                //Get a list of the sub-directories in the directory.
                DirectoryInfo[] folders = directoryObject.GetDirectories();

                //Pushes each folder on to remote device.
                foreach (DirectoryInfo directoryInfo in folders)
                {
                    //Calls the function recursively
                    SendFolderObject(directoryInfo.FullName);
                    //Set the current folder on remote device to that of the parent.
                    SetCurrentFolder(FTPMessages.ParentFolder);
                }
            }

            /// <summary>
            /// Creates the folder structure and transfers 
            /// contents of the pulled folder on local device.
            /// </summary>
            /// <param name="remoteFolderPath">Location of folder to be pulled 
            /// from remote device. </param>
            /// <param name="localFolderPath">Location on local device where 
            /// the pulled folder will be created.</param>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            private void GetFolderObject(string remoteFolderPath, string localFolderPath)
            {

                //Split the folderPath on Directory Seperator.
                char[] delimiters = new char[] { '\\' };
                string[] folders = remoteFolderPath.Split(delimiters);
                bool bRoot = false;

                //Indicates the first directory is root folder.  
                //Set the flag bRoot to true.
                if (folders[0] == string.Empty)
                    bRoot = true;

                //Traverse the folder hierarchy. Set the current 
                //directory on remote device.
                for (int i = 0; i < folders.Length - 1; i++)
                {
                    //Ignore any further occurences of empty strings.
                    if (folders[i] == string.Empty && i != 0 && bRoot)
                        continue;

                    if (!SetCurrentFolder(folders[i]))

                        throw new ArgumentException
                            (FTPMessages.ErrorMsgInvalidRemoteFolderPath,
                             FTPMessages.RemoteFolderPath);
                }

                string folderName = folders[folders.Length - 1];

                if (string.IsNullOrEmpty(folderName))
                {
                    throw new ArgumentException
                          (FTPMessages.ErrorMsgInvalidRemoteFolderPath,
                           FTPMessages.RemoteFolderPath);
                }
                //Set the current folder on remote device
                if (SetCurrentFolder(folderName))
                {
                    //Create the same folder on the local device.
                    DirectoryInfo dir = Directory.CreateDirectory
                                             (localFolderPath +
                                              "\\" +
                                              folderName);


                    //Append the folderName to the localFolderPath
                    localFolderPath = localFolderPath + "\\" + folderName;

                    XmlDocument doc = null;
                    //Get FolderListing of the current folder
                    doc = GetCurrentFolderListingObject();

                    if (doc != null)
                    {
                        //Get a list of folders
                        XmlNodeList folderList =
                                doc.GetElementsByTagName(FTPMessages.Folder);
                        //Get a list of files
                        XmlNodeList fileList =
                                doc.GetElementsByTagName(FTPMessages.File);

                        //For each file in the list get its contents and then create a file on local
                        //device with received file content.
                        if (fileList != null && fileList.Count != 0)
                        {
                            foreach (XmlNode node in fileList)
                            {
                                XmlAttributeCollection attrCollection =
                                                        node.Attributes;
                                if (attrCollection != null &&
                                        attrCollection.Count != 0)
                                {
                                    XmlNode attrNode =
                                      attrCollection.GetNamedItem(FTPMessages.Name);
                                    if (attrNode != null)
                                    {
                                        //Get the file contents
                                        byte[] fileData = GetFileObject(attrNode.Value);
                                        //Write to the local file.
                                        File.WriteAllBytes
                                                    (localFolderPath +
                                                     "\\" +
                                                     attrNode.Value, fileData);

                                    }
                                }

                            }
                        }
                        //For each folder in the list create a folder on local device.
                        if (folderList != null && folderList.Count != 0)
                        {
                            foreach (XmlNode node in folderList)
                            {
                                XmlAttributeCollection attrCollection = node.Attributes;
                                if (attrCollection != null &&
                                    attrCollection.Count != 0)
                                {
                                    XmlNode attrNode =
                                       attrCollection.GetNamedItem(FTPMessages.Name);
                                    if (attrNode != null)
                                    {
                                        //Get folder object
                                        GetFolderObject(attrNode.Value,
                                                        localFolderPath +
                                                        "\\");
                                        //Set Parent folder
                                        SetCurrentFolder(FTPMessages.ParentFolder);
                                    }
                                }
                            }
                        }

                    }
                }

            }

            /// <summary>
            /// Pulls the specified file from the device.
            /// </summary>
            /// <param name="remoteFilePath">Location of the file to be pulled
            /// from remote device.</param>
            /// <returns>Returns a byte array containing the file data.</returns>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            private byte[] GetFileObject(string remoteFilePath)
            {
                byte[] fileData = new byte[] { };

                uint receivedLengthOfFile = 0;

                MemoryStream fileStream = new MemoryStream();
                BinaryWriter fileWriter = new BinaryWriter(fileStream);

                //Split the folderPath on Directory Seperator. 
                char[] delimeters = new char[] { '\\' };
                string[] folders = remoteFilePath.Split(delimeters);
                bool bRoot = false;

                //Indicates the first directory is root folder.  
                //Set the flag bRoot to true.
                if (folders[0] == string.Empty)
                    bRoot = true;

                //Traverse the folder hierarchy. Set the current 
                //directory on remote device.
                for (int i = 0; i < folders.Length - 1; i++)
                {
                    //Ignore any further occurences of empty strings.
                    if (folders[i] == string.Empty && i != 0 && bRoot)
                        continue;

                    if (!SetCurrentFolder(folders[i]))

                        throw new ArgumentException
                             (FTPMessages.ErrorMsgInvalidRemoteFilePath,
                              FTPMessages.RemoteFilePath);
                }

                string fileName = folders[folders.Length - 1];

                if (string.IsNullOrEmpty(fileName))
                    throw new ArgumentException(FTPMessages.RemoteFilePath,
                                                FTPMessages.RemoteFilePath);

                bool continueGet = false;

                do
                {
                    // Create the Get Default Object request.
                    ObjectExchangeItem obexReq =
                        new ObjectExchangeItem(ObjectExchangeOpcode.GetFinal);
                    if (!continueGet)
                    {
                        //Add connectionId header
                        obexReq.AddHeader
                            (ObjectExchangeHeaderType.ConnectionID, this.connectionId);

                        //Add Name header
                        obexReq.AddHeader
                            (ObjectExchangeHeaderType.Name, fileName);
                    }

                    MemoryStream responseStream = new MemoryStream();
                    try
                    {

                        // Send the Get request.
                        this.netwrkStream.Write(obexReq.GetByteStream(),
                                           0,
                                           obexReq.PacketSize);

                        //Sleep for 1 second till all data is put on stream.                        
                        Thread.Sleep(1000);
                        while (!this.netwrkStream.DataAvailable)
                            continue;

                        // Read the response.
                        while (this.netwrkStream.DataAvailable)
                            responseStream.WriteByte((byte)this.netwrkStream.ReadByte());

                        responseStream.Seek(0, SeekOrigin.Begin);

                    }
                    catch (IOException ioEx)
                    {

                        throw new ObjectExchangeException
                            (ObjectExchangeErrorType.StreamError,
                             FTPMessages.ErrorMsgWritetoStream,
                             ioEx);

                    }
                    catch (ObjectDisposedException objEx)
                    {

                        throw new ObjectExchangeException
                            (ObjectExchangeErrorType.StreamError,
                             FTPMessages.ErrorMsgWritetoStream,
                             objEx);

                    }
                    ObjectExchangeItem obexRes =
                                new ObjectExchangeItem(responseStream);

                    if (obexRes.Opcode == ObjectExchangeOpcode.Continue ||
                       obexRes.Opcode == ObjectExchangeOpcode.ContinueFinal)
                    {
                        if (obexRes.HeaderTypeExists
                                                (ObjectExchangeHeaderType.Length))

                            receivedLengthOfFile = ObjectExchangeHelper.FormatUInt32
                                        (BitConverter.ToUInt32(obexRes.GetHeader
                                                (ObjectExchangeHeaderType.Length), 0));

                        if (obexRes.HeaderTypeExists(ObjectExchangeHeaderType.Body))
                            fileWriter.Write
                                (obexRes.GetHeader(ObjectExchangeHeaderType.Body));
                        continueGet = true;
                    }

                    if (obexRes.Opcode == ObjectExchangeOpcode.Success ||
                       obexRes.Opcode == ObjectExchangeOpcode.SuccessFinal)
                    {
                        if (obexRes.HeaderTypeExists(ObjectExchangeHeaderType.EndOfBody))
                            fileWriter.Write
                                    (obexRes.GetHeader
                                                (ObjectExchangeHeaderType.EndOfBody));

                        // Get the file contents.
                        fileData = fileStream.ToArray();
                        fileWriter.Close();

                        if (receivedLengthOfFile > 0 &&
                                fileData.Length != receivedLengthOfFile)
                            throw new ObjectExchangeException
                                (ObjectExchangeErrorType.StreamError,
                                FTPMessages.ErrorMsgIncompleteFile);
                        continueGet = false;
                    }
                    else
                    {
                        ObjectExchangeHelper.RaiseObjectExchangeError
                                                       (obexRes.Opcode);
                        
                    }
                   
                }

                while (continueGet);
                return fileData;
            }



            /// <summary>
            /// Traverses the remoteFolderPath and creates the folder on the 
            /// remote device.            
            /// </summary>
            /// <param name="remoteFolderPath">Location of the folder to be 
            /// created</param>        
            /// <param name="createParentDirectories">Flag indicating if 
            /// non-existing parent directories have to be created.</param>  
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            private void CreateFolderStructure(string remoteFolderPath,
                                                bool createParentDirectories)
            {
                bool directoryExists = false;

                //Split the folderPath on Directory Seperator.
                char[] delimeters = new char[] { '\\' };
                string[] folders = remoteFolderPath.Split(delimeters);

                //Verifies if all folders in remoteFolderPath exist.
                string folderName = folders[folders.Length - 1];
                bool bRoot = false;

                //Indicates the first directory is root folder.  
                //Set the flag bRoot to true.
                if (folders[0] == string.Empty)
                    bRoot = true;

                //Traverse the folder hierarchy. Set the current 
                //directory on remote device.
                for (int i = 0; i < folders.Length - 1; i++)
                {
                    //Ignore any further occurences of empty strings.
                    if (folders[i] == string.Empty && i != 0 && bRoot)
                        continue;

                    directoryExists = SetCurrentFolder(folders[i]);

                    //if folder doesn't exist and createParentDirectories 
                    //flag is true then create folder.

                    if (!directoryExists)
                    {
                        if (createParentDirectories)
                        {
                            CreateFolderObject(folders[i]);
                        }
                        else
                        {
                            //the remote folder path is invalid.
                            throw new ArgumentException
                                (FTPMessages.ErrorMsgInvalidRemoteFolderPath,
                                 FTPMessages.RemoteFolderPath);
                        }
                    }
                    else
                    {
                        continue;
                    }

                }
                //Create the folder.
                CreateFolderObject(folderName);
            }

            /// <summary>
            /// Creates the folder on remote device.
            /// </summary>
            /// <param name="remoteFolderName">Name of the folder to be 
            /// created.</param>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception>
            private void CreateFolderObject(string remoteFolderName)
            {
                ObjectExchangeItem obexReq = null;
                MemoryStream responseStream = null;
                ObjectExchangeItem obexRes = null;

                //Obex packet for create directory request
                obexReq =
                    new ObjectExchangeItem(ObjectExchangeOpcode.SetPath);
                //Add flags field
                obexReq.AddHeader
                    (ObjectExchangeHeaderType.Flags, new byte[] { 0x00 });

                //Add constants field
                obexReq.AddHeader
                    (ObjectExchangeHeaderType.Constants, new byte[] { 0x00 });

                //Add connectionId header
                obexReq.AddHeader
                    (ObjectExchangeHeaderType.ConnectionID, this.connectionId);

                //Add name header
                obexReq.AddHeader
                    (ObjectExchangeHeaderType.Name, remoteFolderName +
                      "\0");


                //Puts request on network stream
                this.netwrkStream.Write(obexReq.GetByteStream(), 0, obexReq.PacketSize);

                //Waits for response
                while (!this.netwrkStream.DataAvailable)
                    continue;

                //Sleep for 1 second till all data is put on stream.                        
                Thread.Sleep(1000);

                //Reads response
                responseStream = new MemoryStream();
                while (this.netwrkStream.DataAvailable)
                    responseStream.WriteByte((byte)this.netwrkStream.ReadByte());


                long position = responseStream.Seek(0, SeekOrigin.Begin);

                obexRes = new ObjectExchangeItem(responseStream);

                if (obexRes.Opcode == ObjectExchangeOpcode.Success ||
                    obexRes.Opcode == ObjectExchangeOpcode.SuccessFinal)
                    return;
                else
                    ObjectExchangeHelper.RaiseObjectExchangeError
                                                    (obexRes.Opcode);

               
            }

            /// <summary>
            /// Traverses the folder path and gets the folder listing.
            /// </summary>
            /// <param name="remoteFolderPath">Location of the folder 
            /// on remote device.</param>
            /// <returns>XmlDocument containing the folder listing.</returns>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            private XmlDocument GetFolderListingObject(string remoteFolderPath)
            {
                if (remoteFolderPath.Equals("\\"))
                    SetCurrentFolder(string.Empty);

                else
                {
                    //Split the folderPath on Directory Seperator.
                    char[] delimiters = new char[] { '\\' };
                    string[] folders = remoteFolderPath.Split(delimiters);
                    bool bRoot = false;

                    //Verify if the first string is a root folder
                    if (folders[0] == string.Empty)
                        bRoot = true;

                    //Traverse the folder hierarchy. Set the current 
                    //directory on remote device.
                    for (int i = 0; i < folders.Length; i++)
                    {
                        //Ignore any further occurences of empty strings.
                        if (folders[i] == string.Empty && i != 0 && bRoot)
                            continue;

                        if (!SetCurrentFolder(folders[i]))
                            throw new ArgumentException
                                (FTPMessages.ErrorMsgInvalidRemoteFolderPath,
                                 FTPMessages.RemoteFolderPath);
                    }
                }
                //Get the current listing of the folder.
                return GetCurrentFolderListingObject();
            }

            /// <summary>
            /// Traverses the remoteFolderPath and Sets the current directory.
            /// </summary>
            /// <param name="remoteFolderPath">Location of the folder to be set
            /// as current directory</param>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the File Transfer operation on remote device.</exception>
            /// <exception cref="ArgumentException">Thrown when 
            /// when one of the arguments provided to the method is not valid.
            /// </exception>
            private void SetCurrentDirectoryObject(string remoteFolderPath)
            {
                if (remoteFolderPath.EndsWith("\\") &&
                          remoteFolderPath.Length > 2)
                    remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Split the folderPath on Directory Seperator.
                char[] delimeters = new char[] { '\\' };
                string[] folders = remoteFolderPath.Split(delimeters);

                //Set to root folder
                if (remoteFolderPath.Equals("\\"))
                    SetCurrentFolder(string.Empty);

                else
                {
                    bool bRoot = false;
                    //Indicates the first directory is root folder.  
                    //Set the flag bRoot to true.
                    if (folders[0] == string.Empty)
                        bRoot = true;

                    //Traverse the folder hierarchy. Set the current 
                    //directory on remote device.
                    for (int i = 0; i <= folders.Length - 1; i++)
                    {
                        //Ignore any further occurences of empty strings.
                        if (folders[i] == string.Empty && i != 0 && bRoot)
                            continue;

                        if (!SetCurrentFolder(folders[i]))
                            throw new ArgumentException
                                    (FTPMessages.ErrorMsgInvalidRemoteFolderPath,
                                     FTPMessages.RemoteFolderPath);
                    }
                }
            }

            /// <summary>
            /// Traverses the remoteFolderPath and deletes the folder
            /// </summary>
            /// <param name="remoteFolderPath">Location of folder on remote 
            /// device. </param>
            /// <param name="deleteSubDirectories">Flag indicating if sub-directories 
            /// have to be deleted.</param>
            /// <exception cref="ArgumentException">Thrown when one of the arguments 
            /// provided to the method is not valid.. </exception>
            /// <exception cref="ObjectExchangeException">Thrown when an error has occured 
            /// while performing the operation on remote device. </exception>            
            private void DeleteFolderObject(string remoteFolderPath,
                                            bool deleteSubDirectories)
            {
                string folderName = string.Empty;

                if (remoteFolderPath.EndsWith("\\") &&
                                      remoteFolderPath.Length > 2)
                    remoteFolderPath =
                             remoteFolderPath.Remove(remoteFolderPath.Length - 1);

                //Split the folderPath on Directory Seperator.
                char[] delimeters = new char[] { '\\' };
                string[] folders = remoteFolderPath.Split(delimeters);
                bool bRoot = false;

                //Indicates the first directory is root folder.  
                //Set the flag bRoot to true.
                if (folders[0] == string.Empty)
                    bRoot = true;

                //Traverse the folder hierarchy. Set the current 
                //directory on remote device.
                for (int i = 0; i < folders.Length - 1; i++)
                {
                    //Ignore any further occurences of empty strings.
                    if (folders[i] == string.Empty && i != 0 && bRoot)
                        continue;

                    if (!SetCurrentFolder(folders[i]))
                        throw new ArgumentException
                          (FTPMessages.ErrorMsgInvalidRemoteFolderPath,
                           FTPMessages.RemoteFolderPath);
                }
                //The last folder in the folderPath is deleted
                folderName = folders[folders.Length - 1];
                if (deleteSubDirectories)
                {
                    //Call the recursive function to delete sub-folders.
                    DeleteWithSubFolders(folderName);
                }
                else
                {
                    //Call the function to delete the specified folder.
                    DeleteObject(folderName);
                }
            }

            /// <summary>
            /// Adds an asynchronous FTP request to the Request Queue.
            /// </summary>
            /// <param name="request">The asynchronous FTP request.</param>

            private void AddRequestToRequestQueue(FTPRequest request)
            {
                //Acquire the exclusive lock on networkStream
                Monitor.Enter(this.requestQueue);
                // Add the request to the list of pending requests.
                this.requestQueue.Add(request);
                //Releases the exclusive lock on networkStream
                Monitor.Exit(this.requestQueue);

                // If the background worker handling asynchronous operations 
                //is not busy, put it to work.
                if (!this.asyncOperationHandler.IsBusy)
                    this.asyncOperationHandler.RunWorkerAsync();
            }

            /// <summary>
            /// Raises the appropriate events and puts the background worker 
            /// to work on any pending asynchronous requests.
            /// </summary>
            /// <param name="sender">The background worker that will process 
            /// this method.</param>
            /// <param name="e">DoWorkEventArgs to store the outcome of the 
            /// operation.</param>

            private void asyncOperationHandler_DoWork(object sender,
                                                      DoWorkEventArgs e)
            {
                //Acquire an exclusive lock on the requestQueue. 
                Monitor.Enter(this.requestQueue);
                if (this.requestQueue.Count != 0)
                {
                    // Get the 1st request from the list of pending 
                    //asynchronous operations.
                    try
                    {
                        this.runningAsyncRequest = this.requestQueue[0];

                        // Remove it from the list.
                        this.requestQueue.RemoveAt(0);
                    }
                    finally
                    {
                        //Releases the exclusive lock on requestQueue
                        Monitor.Exit(this.requestQueue);
                    }

                    if (this.asyncOperationHandler.CancellationPending)
                        e.Cancel = true;

                    else
                    {
                        // Raise the appropriate begin event and perform the 
                        //operation.                       
                        RaiseBeginEvent(this.runningAsyncRequest.RequestType, e);
                    }
                }
            }

            /// <summary>
            ///Event handler for background worker's RunWorkerCompleted event.
            /// This method packs the outcome of an asynchronous operation into
            /// the appropriate EventArgs and raises the operation's Completed 
            /// event if implemented. It then puts the background worker to work
            /// on any pending asynchronous requests from the request queue.
            /// </summary>
            /// <param name="sender">The background worker that will process 
            /// this method.</param>
            /// <param name="e">RunWorkerCompletedEventArgs which stores the 
            /// outcome of the operation.</param>
            private void asyncOperationHandler_RunWorkerCompleted(object sender,
                                                   RunWorkerCompletedEventArgs e)
            {
                if (this.runningAsyncRequest != null)
                {
                    // Raise the appropriate event.
                    switch (this.runningAsyncRequest.RequestType)
                    {
                        case FTPRequestType.GetFile:
                            if (this.GetFileCompleted != null)
                            {
                                Exception ftpException = null;
                                byte[] fileContents = new byte[0];

                                //If an error has occured then set exception 
                                //parameter of completed event
                                if (e.Error != null)
                                {
                                    ftpException = e.Error;
                                }

                                else if (!e.Cancelled && e.Result != null && (e.Result is Exception))
                                {
                                    ftpException = (Exception)e.Result;
                                }
                                else
                                    fileContents = (byte[])e.Result;
                                // Raise the event.
                                GetFileCompleted(this,
                                                    new GetFileCompletedEventArgs(
                                                        this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                        fileContents,
                                                        ftpException,
                                                        e.Cancelled,
                                                        this.runningAsyncRequest.UserState));
                            }
                            break;

                        case FTPRequestType.GetFolder:
                            if (this.GetFolderCompleted != null)
                            {
                                Exception ftpException = null;

                                //If an error has occured then set exception 
                                //parameter of completed event
                                if (e.Error != null)
                                    ftpException = e.Error;

                                else if (!e.Cancelled && e.Result != null && (e.Result is Exception))
                                    ftpException = (Exception)e.Result;

                                // Raise the event.
                                GetFolderCompleted(this,
                                                    new GetFolderCompletedEventArgs(
                                                        this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                        this.runningAsyncRequest.RequestParameters[1].ToString(),
                                                        ftpException,
                                                        e.Cancelled,
                                                        this.runningAsyncRequest.UserState));
                            }
                            break;


                        case FTPRequestType.SendFile:
                            if (this.SendFileCompleted != null)
                            {

                                Exception ftpException = null;

                                //If an error has occured then set exception 
                                //parameter of completed event
                                if (e.Error != null)
                                    ftpException = e.Error;

                                else if (!e.Cancelled && e.Result != null && (e.Result is Exception))
                                    ftpException = (Exception)e.Result;

                                // Raise the event.
                                SendFileCompleted(this,
                                                    new SendFileCompletedEventArgs(
                                                        this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                        ftpException,
                                                        e.Cancelled,
                                                        this.runningAsyncRequest.UserState));
                            }

                            break;



                        case FTPRequestType.SendFolder:
                            if (this.SendFolderCompleted != null)
                            {
                                Exception ftpException = null;
                                //If an error has occured then set exception 
                                //parameter of completed event
                                if (e.Error != null)
                                    ftpException = e.Error;

                                else if (!e.Cancelled && e.Result != null && (e.Result is Exception))
                                    ftpException = (Exception)e.Result;

                                // Raise the event.
                                SendFolderCompleted(this,
                                                    new SendFolderCompletedEventArgs(
                                                        this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                        ftpException,
                                                        e.Cancelled,
                                                        this.runningAsyncRequest.UserState));
                            
                            }

                            break;
                        case FTPRequestType.DeleteFile:
                            if (this.DeleteFileCompleted != null)
                            {
                                Exception ftpException = null;
                                //If an error has occured then set exception 
                                //parameter of completed event
                                if (e.Error != null)
                                    ftpException = e.Error;

                                else if (!e.Cancelled && e.Result != null &&
                                        (e.Result is Exception))
                                    ftpException = (Exception)e.Result;

                                // Raise the event.
                                DeleteFileCompleted(this,
                                                    new DeleteFileCompletedEventArgs(
                                                     this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                     ftpException,
                                                     e.Cancelled,
                                                     this.runningAsyncRequest.UserState));
                            }

                            break;
                        case FTPRequestType.DeleteFolder:
                            if (this.DeleteFolderCompleted != null)
                            {
                                Exception ftpException = null;

                                //If an error has occured then set exception 
                                //parameter of completed event
                                if (e.Error != null)
                                    ftpException = e.Error;

                                else if (!e.Cancelled && e.Result != null &&
                                        (e.Result is Exception))
                                    ftpException = (Exception)e.Result;

                                // Raise the event.
                                DeleteFolderCompleted(this,
                                                    new DeleteFolderCompletedEventArgs(
                                                        this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                        (bool)this.runningAsyncRequest.RequestParameters[1],
                                                        ftpException,
                                                        e.Cancelled,
                                                        this.runningAsyncRequest.UserState));
                            }

                            break;

                        case FTPRequestType.CreateFolder:
                            if (this.CreateFolderCompleted != null)
                            {
                                Exception ftpException = null;

                                //If an error has occured then set exception 
                                //parameter of completed event
                                if (e.Error != null)
                                    ftpException = e.Error;

                                else if (!e.Cancelled && e.Result != null && (e.Result is Exception))
                                    ftpException = (Exception)e.Result;

                                // Raise the event.
                                CreateFolderCompleted(this,
                                                    new CreateFolderCompletedEventArgs(
                                                        this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                        (bool)this.runningAsyncRequest.RequestParameters[1],
                                                        ftpException,
                                                        e.Cancelled,
                                                        this.runningAsyncRequest.UserState));
                            }

                            break;
                        case FTPRequestType.SetCurrentDirectory:
                            if (this.SetCurrentDirectoryCompleted != null)
                            {
                                Exception ftpException = null;

                                //If an error has occured then set exception 
                                //parameter of completed event
                                if (e.Error != null)
                                    ftpException = e.Error;

                                else if (!e.Cancelled && e.Result != null && (e.Result is Exception))
                                    ftpException = (Exception)e.Result;


                                // Raise the event.
                                SetCurrentDirectoryCompleted(this,
                                                    new SetCurrentDirectoryCompletedEventArgs(
                                                        this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                        ftpException,
                                                        e.Cancelled,
                                                        this.runningAsyncRequest.UserState));
                            }

                            break;
                        case FTPRequestType.GetFolderListing:
                            if (this.GetFolderListingCompleted != null)
                            {
                                Exception ftpException = null;
                                XmlDocument folderListing = new XmlDocument();

                                //If an error has occured then set exception 
                                //parameter of completed event
                                if (e.Error != null)
                                    ftpException = e.Error;

                                else if (!e.Cancelled && e.Result != null && (e.Result is Exception))
                                    ftpException = (Exception)e.Result;

                                else
                                    folderListing = (XmlDocument)e.Result;

                                // Raise the event.
                                GetFolderListingCompleted(this,
                                                    new GetFolderListingCompletedEventArgs(
                                                        this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                        folderListing,
                                                        ftpException,
                                                        e.Cancelled,
                                                        this.runningAsyncRequest.UserState));
                            }
                            break;

                    }


                }

                // If there are pending asynchronous requests, set the 
                //background worker to work on them.
                if (this.requestQueue.Count > 0)
                    this.asyncOperationHandler.RunWorkerAsync();
            }

            /// <summary>
            /// Raises the begin event and performs the operation as specified 
            /// by the ftpRequestType variable.
            /// </summary>
            /// <param name="ftpRequestType">Specifies the operation to 
            /// be performed</param>
            /// <param name="e">EventArgs of Begin event.</param>
            private void RaiseBeginEvent(FTPRequestType ftpRequestType,
                                         DoWorkEventArgs e)
            {
                switch (ftpRequestType)
                {
                    case FTPRequestType.GetFile:
                        // Raise the GetFile Begin event if required.
                        if (this.GetFileBegin != null)
                        {
                            GetFileBegin(this,
                                         new GetFileBeginEventArgs
                                         (this.runningAsyncRequest.RequestParameters[0].ToString(),
                                          this.runningAsyncRequest.UserState));
                        }
                        //Acquire an exclusive lock on the netwrkStream. 
                        Monitor.Enter(this.netwrkStream);

                        try
                        {
                            // Perform the operation.
                            byte[] fileContent =
                                GetFileObject
                                    (this.runningAsyncRequest.RequestParameters[0].ToString());
                            e.Result = fileContent;
                        }
                        catch (Exception ex)
                        {
                            e.Result = ex;
                        }
                        finally
                        {
                            //Releases the exclusive lock on networkStream
                            Monitor.Exit(this.netwrkStream);

                        }
                        break;

                    case FTPRequestType.GetFolder:
                        {
                            // Raise the GetFolderBegin event if required.
                            if (this.GetFolderBegin != null)
                            {
                                GetFolderBegin(this,
                                  new GetFolderBeginEventArgs(
                                  this.runningAsyncRequest.RequestParameters[0].ToString(),
                                  this.runningAsyncRequest.RequestParameters[1].ToString(),
                                  this.runningAsyncRequest.UserState));
                            }
                            //Acquire an exclusive lock on the networkStream. 
                            Monitor.Enter(this.netwrkStream);


                            try
                            {
                                GetFolderObject
                                 (this.runningAsyncRequest.RequestParameters[0].ToString(),
                                  this.runningAsyncRequest.RequestParameters[1].ToString());
                            }
                            catch (Exception ex)
                            {
                                e.Result = ex;
                            }
                            finally
                            {
                                //Releases the exclusive lock on networkStream
                                Monitor.Exit(this.netwrkStream);

                            }
                        }
                        break;

                    case FTPRequestType.SendFile:
                        {
                            // Raise the SendFileBegin event if required.
                            if (this.SendFileBegin != null)
                            {
                                SendFileBegin(this,
                                    new SendFileBeginEventArgs
                                    (this.runningAsyncRequest.RequestParameters[0].ToString(),
                                    this.runningAsyncRequest.UserState));

                            }
                            //Acquire an exclusive lock on the networkStream. 
                            Monitor.Enter(this.netwrkStream);


                            try
                            {
                                if (this.runningAsyncRequest.RequestParameters.Length == 2 &&
                                    this.runningAsyncRequest.RequestParameters[1] is MemoryStream)
                                    SendFileObject
                                        ((MemoryStream)this.runningAsyncRequest.RequestParameters[1],
                                           this.runningAsyncRequest.RequestParameters[0].ToString());
                                else
                                    // Perform the operation.
                                    SendFileObject
                                        (this.runningAsyncRequest.RequestParameters[0].ToString());
                            }
                            catch (Exception ex)
                            {
                                e.Result = ex;
                            }
                            finally
                            {
                                //Releases the exclusive lock on networkStream
                                Monitor.Exit(this.netwrkStream);

                            }

                        }
                        break;

                    case FTPRequestType.SendFolder:
                        {
                            // Raise the SendFolderBegin event if required.
                            if (this.SendFolderBegin != null)
                            {
                                SendFolderBegin(this,
                                        new SendFolderBeginEventArgs(
                                                this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                this.runningAsyncRequest.UserState));
                            }

                            //Acquire an exclusive lock on the networkStream. 
                            Monitor.Enter(this.netwrkStream);


                            try
                            {
                                SendFolderObject(this.runningAsyncRequest.RequestParameters[0].ToString());
                            }
                            catch (Exception ex)
                            {
                                e.Result = ex;
                            }
                            finally
                            {
                                //Releases the exclusive lock on networkStream
                                Monitor.Exit(this.netwrkStream);
                            }

                        }
                        break;

                    case FTPRequestType.DeleteFile:
                        {
                            // Raise the DeleteFileBegin event if required.
                            if (this.DeleteFileBegin != null)
                            {
                                DeleteFileBegin(this,
                                        new DeleteFileBeginEventArgs(
                                                this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                 this.runningAsyncRequest.UserState));
                            }
                            //Acquire an exclusive lock on the networkStream. 
                            Monitor.Enter(this.netwrkStream);

                            // Perform the operation.
                            try
                            {
                                DeleteFileObject(this.runningAsyncRequest.RequestParameters[0].ToString());
                            }
                            catch (Exception ex)
                            {
                                e.Result = ex;
                            }
                            finally
                            {
                                //Releases the exclusive lock on networkStream
                                Monitor.Exit(this.netwrkStream);

                            }

                        }
                        break;

                    case FTPRequestType.DeleteFolder:
                        {
                            // Raise the DeleteFolderBegin event if required.
                            if (this.DeleteFolderBegin != null)
                            {
                                DeleteFolderBegin(this,
                                        new DeleteFolderBeginEventArgs(
                                                this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                (bool)this.runningAsyncRequest.RequestParameters[1],
                                                this.runningAsyncRequest.UserState));
                            }
                            //Acquire an exclusive lock on the networkStream. 
                            Monitor.Enter(this.netwrkStream);


                            try
                            {
                                // Perform the operation.
                                DeleteFolderObject
                                    (this.runningAsyncRequest.RequestParameters[0].ToString(),
                                    (bool)this.runningAsyncRequest.RequestParameters[1]);
                            }
                            catch (Exception ex)
                            {
                                e.Result = ex;
                            }
                            finally
                            {
                                //Releases the exclusive lock on networkStream
                                Monitor.Exit(this.netwrkStream);
                            }
                        }
                        break;
                    case FTPRequestType.CreateFolder:
                        {
                            // Raise the CreateFolderBegin event if required.
                            if (this.CreateFolderBegin != null)
                            {
                                CreateFolderBegin(this,
                                        new CreateFolderBeginEventArgs(
                                                this.runningAsyncRequest.RequestParameters[0].ToString(),
                                                (bool)this.runningAsyncRequest.RequestParameters[1],
                                                this.runningAsyncRequest.UserState));
                            }
                            //Acquire an exclusive lock on the networkStream. 
                            Monitor.Enter(this.netwrkStream);


                            try
                            {
                                // Perform the operation.
                                CreateFolderStructure
                                    (this.runningAsyncRequest.RequestParameters[0].ToString(),
                                    (bool)this.runningAsyncRequest.RequestParameters[1]);
                            }
                            catch (Exception ex)
                            {
                                e.Result = ex;
                            }
                            finally
                            {
                                //Releases the exclusive lock on networkStream
                                Monitor.Exit(this.netwrkStream);

                            }
                        }
                        break;
                    case FTPRequestType.SetCurrentDirectory:
                        {
                            // Raise the SetCurrentDirectoryBegin event if required.
                            if (this.SetCurrentDirectoryBegin != null)
                            {
                                SetCurrentDirectoryBegin(this,
                                        new SetCurrentDirectoryBeginEventArgs(
                                          this.runningAsyncRequest.RequestParameters[0].ToString(),
                                          this.runningAsyncRequest.UserState));
                            }

                            //Acquire an exclusive lock on the networkStream. 
                            Monitor.Enter(this.netwrkStream);


                            try
                            {
                                // Perform the operation.
                                SetCurrentDirectoryObject
                                    (this.runningAsyncRequest.RequestParameters[0].ToString());
                            }
                            catch (Exception ex)
                            {
                                e.Result = ex;
                            }
                            finally
                            {
                                //Releases the exclusive lock on networkStream
                                Monitor.Exit(this.netwrkStream);
                            }
                        }
                        break;
                    case FTPRequestType.GetFolderListing:
                        {
                            // Raise the SetCurrentDirectoryBegin event if required.
                            if (this.GetFolderListingBegin != null)
                            {
                                GetFolderListingBegin(this,
                                        new GetFolderListingBeginEventArgs
                                         (this.runningAsyncRequest.RequestParameters[0].ToString(),
                                         this.runningAsyncRequest.UserState));
                            }
                            //Acquire an exclusive lock on the networkStream. 
                            Monitor.Enter(this.netwrkStream);

                            try
                            {
                                // Perform the operation.
                                XmlDocument folderListing =
                                    GetFolderListingObject
                                        (this.runningAsyncRequest.RequestParameters[0].ToString());

                                e.Result = folderListing;
                            }
                            catch (Exception ex)
                            {
                                e.Result = ex;
                            }
                            finally
                            {
                                //Releases the exclusive lock on networkStream
                                Monitor.Exit(this.netwrkStream);
                            }
                        }
                        break;

                }
            }

            #endregion

            #region Public Properties
            /// <summary>
            /// Gets or sets the network stream used for communicating with a remote device.
            /// </summary>
            [Browsable(false)]
            public NetworkStream NetworkStream
            {
                get
                { return this.netwrkStream; }
                set
                { this.netwrkStream = value; }
            }

            #endregion
        }
    }
}